#include "../include/MappingRelationManager.h"
#include "CLogger.h"

CMappingRelationManager   CMappingRelationManager::c_mapingRelationMana;

CMappingRelationManager::CMappingRelationManager()
{
}

CMappingRelationManager::~CMappingRelationManager()
{
}

CMappingRelationManager*  CMappingRelationManager::getInstance()
{
    return &c_mapingRelationMana;
}

void CMappingRelationManager::init(std::shared_ptr<CConfigManager> cm)
{
    c_cm = cm;
}

void CMappingRelationManager::build_dc_iec104_relevance(std::list<ST_SINGLE_MODEL_INFO>& lstModelsInfo, std::list<ST_REGISTER_MODEL_INFO>& lstRegisterRelation)
{
    auto iec104InfoObjs = c_cm->get_104_info_objs();
    if (iec104InfoObjs == nullptr){
        return;
    }
    //无104信息对象，不处理
    if (iec104InfoObjs->size() ==0)
    {
        CLogger::getInstance()->log_i("build_dc_iec104_relevance:no iec104 objs.");
        return;
    }

    c_dc_dev_104InfoObjs.clear();
    //map<model,vector<name>>
    std::unordered_map<std::string, std::vector<std::string>>   mpModelPtname;
    for (auto itm = lstModelsInfo.begin(); itm != lstModelsInfo.end(); itm++)
    {
        auto itfind = mpModelPtname.find(itm->model);
        if (itfind == mpModelPtname.end())
        {
            std::vector<std::string>  ptNames;
            for (auto itpt = itm->lstModelptInfo.begin(); itpt != itm->lstModelptInfo.end(); itpt++)
            {
                ptNames.push_back(itpt->name);
            }
            mpModelPtname.insert(make_pair(itm->model, ptNames));
        }
    }

    for (auto itreg = lstRegisterRelation.begin(); itreg != lstRegisterRelation.end(); itreg++)
    {
        std::string model =   itreg->model;
        for (auto itDev = itreg->lstRegModels.begin(); itDev != itreg->lstRegModels.end(); itDev++)
        {
            std::string  strdev = itDev->dev;
            auto itf = mpModelPtname.find(model);
            if (itf != mpModelPtname.end())
            {
                append_dev_datapt(strdev, itf->second, iec104InfoObjs);
            }
        }

    }

}
//创建设备id、数据点id的死区映射<dev_id，<point_id，deadzone>>
void CMappingRelationManager::build_iec104_deadzonemp()
{
    auto iec104InfoObjs = c_cm->get_104_info_objs();
    if (iec104InfoObjs == nullptr){
        return;
    }
    //无104信息对象，不处理
    if (iec104InfoObjs->size() == 0)
    {
        return;
    }

    for (auto ito = iec104InfoObjs->begin(); ito != iec104InfoObjs->end(); ito++)
    {
        auto itd = c_iec104_pts_deadzone.find(ito->second.terminal_id);
        if (itd == c_iec104_pts_deadzone.end())
        {
            std::unordered_map<int64_t, double> mpDeadzone;
            mpDeadzone.insert(std::make_pair(ito->second.point_id, ito->second.deadzone));
            c_iec104_pts_deadzone.insert(std::make_pair(ito->second.terminal_id, mpDeadzone));
        }
        else{
            auto itv = itd->second.find(ito->second.point_id);
            if (itv == itd->second.end())
            {
                itd->second.insert(std::make_pair(ito->second.point_id,ito->second.deadzone));
            }
            else{
                itd->second[ito->second.point_id] = ito->second.deadzone;
            }
        }
    }
}

double CMappingRelationManager::get_point_deadzone(int64_t dev_id, int64_t point_id)
{
    double deadzone = 0.0;
    auto  itp = c_iec104_pts_deadzone.find(dev_id);
    if (itp != c_iec104_pts_deadzone.end())
    {
        auto itd = itp->second.find(point_id);
        if (itd != itp->second.end())
        {
            deadzone = itd->second;
        }
    }

    return deadzone;
}

void CMappingRelationManager::append_dev_datapt(std::string dev, std::vector<std::string> data_names, IEC104_INFO_OBJECT_PTR iec104objs)
{
    //modbus采集点
    auto modbus_pts = c_cm->get_modbus_points();
    for (auto itn = data_names.begin(); itn != data_names.end(); itn++)
    {
        std::string pt_name = *itn;
        for (auto itmod = modbus_pts->begin(); itmod != modbus_pts->end(); itmod++)
        {
            //在modbus_points中找到对应的点
            if (itmod->second.name.compare(pt_name.c_str()) == 0)
            {
                for (auto it104 = iec104objs->begin(); it104 != iec104objs->end(); it104++)
                {
                    //在104信息对象中找到对应的信息对象
                     if ((it104->second.point_id == itmod->second.id) ) 
                     {
                         ST_104_INFO_OBJECT st104InfoObj = it104->second;

                         auto itfind = c_dc_dev_104InfoObjs.find(dev);
                         if (itfind != c_dc_dev_104InfoObjs.end())
                         {
                             itfind->second.insert(make_pair(pt_name,st104InfoObj));
                             CLogger::getInstance()->log_d("append_dev_datapt:[%s,[%s,%d]]", dev.c_str(), pt_name.c_str(), st104InfoObj.info_addr);
                         }
                         else{
                             T_DC_NAME_104INFO_OBJ mpDc104Obj;
                             mpDc104Obj.insert(make_pair(pt_name,st104InfoObj));
                             c_dc_dev_104InfoObjs.insert(make_pair(dev, mpDc104Obj));

                             CLogger::getInstance()->log_d("append_dev_datapt:[%s,[%s,%d]]",dev.c_str(),pt_name.c_str(),st104InfoObj.info_addr);
                         }
                         //保存<pointid,pointname>
                         auto itp = c_modbus_points.find(itmod->second.id);
                         if (itp == c_modbus_points.end())
                         {
                             c_modbus_points.insert(std::make_pair(itmod->second.id, pt_name));

                             CLogger::getInstance()->log_d("append_dev_datapt,modbus point id=%lld,name=%s",itmod->second.id,pt_name.c_str());
                         }
                         break;
                     }
                 }
            }
        }
    }
}

std::shared_ptr<ST_104_INFO_OBJECT> CMappingRelationManager::get_iec104Obj_with_dev_ptname(std::string& dev, std::string& ptname)
{
    m_thdnotify_iec104obj.lock();
    CLogger::getInstance()->log_d("get_iec104Obj_with_dev_ptname,dev=%s,ptname=%s", dev.c_str(), ptname.c_str());

    ST_104_INFO_OBJECT  st104InfoObj;
    auto itf = c_dc_dev_104InfoObjs.find(dev);
    if (itf != c_dc_dev_104InfoObjs.end())
    {
        auto itobj = itf->second.find(ptname);
        if (itobj != itf->second.end())
        {
            st104InfoObj = itobj->second;

            m_thdnotify_iec104obj.unlock();
            return std::make_shared<ST_104_INFO_OBJECT>(st104InfoObj);
        }
    }
    m_thdnotify_iec104obj.unlock();

    return nullptr;
}

void CMappingRelationManager::build_iec104_down_relevance()
{
    auto iec104InfoObjs = c_cm->get_104_info_objs(); 
    if ((nullptr == iec104InfoObjs)  || (iec104InfoObjs->size() ==0))
    {
        CLogger::getInstance()->log_i("build_iec104_down_relevance, get iec104obj error or size is 0");
        return;
    }

    for (auto itobj = iec104InfoObjs->begin(); itobj != iec104InfoObjs->end(); itobj++)
    {
        int64_t dev_id = itobj->second.terminal_id;
        auto dev = c_cm->get_terminal_device(dev_id);
        if (nullptr ==dev) {
            CLogger::getInstance()->log_i("build_iec104_down_relevance, get dev(id=%lld) error.",dev_id);
            continue;
        }
        auto proto = c_cm->get_protocol_rule(dev->protocol_id);
        if (nullptr == proto) {
            CLogger::getInstance()->log_i("build_iec104_down_relevance, get protocol(id=%lld) error.", dev->protocol_id);
            continue;
        }
        if (1 == proto->protocol_type)  //modbus
        {
            auto modbus_cmd = c_cm->get_modbus_command(itobj->second.point_id);
            if (nullptr != modbus_cmd)
            {
                ST_IEC104_DOWN_CMD  st104downCmd;
                st104downCmd.dev_id = itobj->second.terminal_id;
                st104downCmd.cmd_id = modbus_cmd->id;

                c_iec104_down_cmds.insert(std::make_pair(itobj->second.info_addr, st104downCmd));
            }
        }
        else if(2 == proto->protocol_type){  //dlt645
            auto dlt645_cmd = c_cm->get_dlt645_command(itobj->second.point_id);
            if (nullptr != dlt645_cmd)
            {
                ST_IEC104_DOWN_CMD  st104downCmd;
                st104downCmd.dev_id = itobj->second.terminal_id;
                st104downCmd.cmd_id = dlt645_cmd->id;

                c_iec104_down_cmds.insert(std::make_pair(itobj->second.info_addr, st104downCmd));
            }
        }
        else{
            CLogger::getInstance()->log_i("build_iec104_down_relevance,protocol type=%d not suport.", proto->protocol_type);
        }

        
    }
}

std::shared_ptr<ST_IEC104_DOWN_CMD> CMappingRelationManager::get_dev_cmd_withobjaddr(int obj_addr)
{
    ST_IEC104_DOWN_CMD  st104downCmd;
    
    auto itf = c_iec104_down_cmds.find(obj_addr);
    if (itf != c_iec104_down_cmds.end())
    {
        st104downCmd.dev_id = itf->second.dev_id;
        st104downCmd.cmd_id = itf->second.cmd_id;
    }
    else{
        CLogger::getInstance()->log_i("get_dev_cmd_withobjaddr: the obj(addr=%d) down cmd not find.",obj_addr);
    }

    return std::make_shared<ST_IEC104_DOWN_CMD>(st104downCmd);
}

void CMappingRelationManager::build_points_relation()
{
    auto modbus_pts = c_cm->get_modbus_points();
    for (auto itm = modbus_pts->begin(); itm != modbus_pts->end();itm++)
    {
        c_modbus_points.insert(std::make_pair(itm->second.id, itm->second.name));
    }

    auto dlt645_pts = c_cm->get_dlt645_points();
    for (auto itp = dlt645_pts->begin(); itp != dlt645_pts->end();itp++)
    {
        c_dlt645_points.insert(std::make_pair(itp->second.id, itp->second.name));

        //查询点信息在冻结数据上报时使用，只保存645的
        auto itfind = c_frozen_ptinfo.find(itp->second.name);
        if (itfind == c_frozen_ptinfo.end())
        {
            ST_FROZEN_PTINFO  stPtInfo;
            stPtInfo.point_id = itp->second.id;
            stPtInfo.data_type = itp->second.data_type;

            c_frozen_ptinfo.insert(std::make_pair(itp->second.name,stPtInfo));
        }
    }

    auto dlt698_pts = c_cm->get_dlt698_points();
    for (auto it = dlt698_pts->begin(); it != dlt698_pts->end(); it++)
    {
        c_dlt698_points.insert(std::make_pair(it->second.id, it->second.name));
    }
}
std::string CMappingRelationManager::get_point_name(int64_t dev_id, int64_t  point_id)
{
    std::string ptname;

    auto dev = c_cm->get_terminal_device(dev_id);
    if (nullptr ==dev) {
        return "";
    }
    auto proto = c_cm->get_protocol_rule(dev->protocol_id);
    if (nullptr ==proto) {
        return "";
    }

    int proto_type = proto->protocol_type;
    if (1== proto_type)  {
        auto itp = c_modbus_points.find(point_id);
        if (itp != c_modbus_points.end())
        {
            ptname = itp->second;
        }
    }else if (2 ==proto_type)  {
        auto itp = c_dlt645_points.find(point_id);
        if (itp != c_dlt645_points.end())
        {
            ptname = itp->second;
        }
    }else if (3 ==proto_type) {
        auto itp = c_dlt698_points.find(point_id);
        if (itp != c_dlt698_points.end())
        {
            ptname = itp->second;
        }

    }    

    return ptname;
}

std::shared_ptr<ST_FROZEN_PTINFO> CMappingRelationManager::get_point_info(std::string& name)
{
    auto itp = c_frozen_ptinfo.find(name);
    if (itp != c_frozen_ptinfo.end())
    {
        std::shared_ptr<ST_FROZEN_PTINFO> ptinfo = std::make_shared<ST_FROZEN_PTINFO>();
        ptinfo->point_id = itp->second.point_id;
        ptinfo->data_type = itp->second.data_type;

        return ptinfo;
    }
    else{
        return nullptr;
    }
}

std::shared_ptr<MODBUS_COMMAND> CMappingRelationManager::modbus_get_cmd_info(std::string& cmd_name){

    std::shared_ptr<MODBUS_COMMAND> cmd = std::make_shared<MODBUS_COMMAND>();
    auto cmds = c_cm->get_modbus_commands();
    for (auto itm = cmds->begin(); itm != cmds->end(); itm++)
    {
        if (cmd_name.compare(itm->second.name.c_str()) == 0)
        {
            *cmd = itm->second;
            return cmd;
        }
    }
    return nullptr;
}
std::shared_ptr<DLT645_COMMAND> CMappingRelationManager::dlt645_get_cmd_info(std::string& cmd_name){

    std::shared_ptr<DLT645_COMMAND> cmd = std::make_shared<DLT645_COMMAND>();
    auto cmds = c_cm->get_dlt645_commands();
    for (auto itm = cmds->begin(); itm != cmds->end(); itm++)
    {
        if (cmd_name.compare(itm->second.name.c_str()) == 0)
        {
            *cmd = itm->second;
            return cmd;
        }
    }
    return nullptr;
}

std::string CMappingRelationManager::get_comp_addr(std::string & addr, int64_t pid, bool bfrozen)
{
    std::string  comp_addr = addr;
    auto pdev = c_cm->get_terminal_device(pid);
    if (nullptr != pdev)
    {
        char buff[128] = { 0 };
        if (!bfrozen) {
            snprintf(buff, sizeof(buff), "%s_%s", pdev->slave_addr.c_str(), addr.c_str());
        }
        else{
            snprintf(buff, sizeof(buff), "%s_%s", pdev->node_id.c_str(), addr.c_str());
        }
        return std::string(buff);
    }

    return  comp_addr;
}